#pragma once

#include <compl.h>
#include <ddblk/apds.h>
/* 定义benchmark项 */
static word_t volatile ptc = 0;
SAI word_t fetch_add(APDSFUNC_ARGLIST){
	// printf("%lu\n", ptc);
	PARAM_USED(APDSFUNC_ARGUSELIST);
	return ++ptc;
}

#define __DEF_TEST_TYPE(type, append, critical_section, test_nr)\
type##append##_t _##type##_instance ;\
static void *test_##type##_single(void *arg){\
	PARAM_USED(arg);\
	apdsarg_t tmp = { .arg[0] = (paddr_t) (&_##type##_instance) };\
	struct timespec ts;\
	struct timespec td;\
	TIME_STAMP(&ts);\
	for (word_t idx = 0; idx < test_nr; idx++){\
		type##_sync( (apds_t *)&_##type##_instance , critical_section, &tmp);\
	}\
	TIME_STAMP(&td);\
	return (void *)TIME_DELTA_MS(&ts, &td); \
}\
static word_t type##_threads_nr;								\
static void *test_##type##_single_pfunc(void *arg){						\
	word_t target_thread_nr = (word_t)arg;							\
	faa(&type##_threads_nr, 1);								\
	while (atm_ld(&type##_threads_nr) < target_thread_nr);					\
	return test_##type##_single(arg);							\
}												\
static void test_##type (word_t max_threads){							\
	pthread_t p[max_threads];								\
	void *tret[max_threads];								\
	word_t sum;										\
	type##_init(&_##type##_instance, sizeof(_##type##_instance));				\
	printf("\n-----------%s----------\n",#type);						\
	word_t half_threads = 1;								\
	for (word_t thread_nr = 1; thread_nr <= max_threads; thread_nr += half_threads){	\
		atm_st(&type##_threads_nr, 0);							\
		for (word_t idx = 0; idx < thread_nr - 1; idx++){				\
			pthread_create(&p[idx], NULL, test_##type##_single_pfunc, (void *)thread_nr);\
		}										\
		sum = (word_t)test_##type##_single_pfunc((void *)thread_nr);				\
		for (word_t idx = 0; idx < thread_nr - 1; idx++)				\
		{										\
			pthread_join(p[idx], &tret[idx]);					\
		}										\
		for (word_t idx = 0; idx < thread_nr - 1; idx++){				\
			sum += (word_t)tret[idx];						\
		}										\
		printf("[%ldm%d] %ld ms\t\t%f mop/s\n", thread_nr, test_nr , sum/thread_nr, (test_nr * thread_nr) / (1000.0f * sum / thread_nr) );\
		if (thread_nr != 1 && is_powerof2(thread_nr)) half_threads = thread_nr >> 1;	\
	}											\
	type##_destruct((apds_t *)&_##type##_instance);						\
}

#define DEF_TEST_TYPE(type, critical_section, test_nr)		__DEF_TEST_TYPE(type, , critical_section, test_nr)
